importJar("org.slf4j:slf4j-api:jar:1.7.21");
importJar("org.slf4j:slf4j-simple:jar:1.7.21");
importJar('com.jcraft:jsch:jar:0.1.54');
importJar('org.eclipse.jgit:org.eclipse.jgit:jar:4.11.0.201803080745-r');

importClass("com.jcraft.jsch.JSch");
importClass("org.eclipse.jgit.api.Git");
importClass("org.eclipse.jgit.api.ListBranchCommand");
importClass("org.eclipse.jgit.revwalk.RevWalk");
importClass("org.eclipse.jgit.transport.JschConfigSessionFactory");
importClass("org.eclipse.jgit.transport.SshSessionFactory");
importClass("org.eclipse.jgit.treewalk.CanonicalTreeParser");

importClass("java.io.File");
importClass("java.util.List");

// 私钥.
var sshPrivateKeyPath = System.getProperty("private.key");
if (null == sshPrivateKeyPath) {
    sshPrivateKeyPath = System.getProperty("user.home").replace("\\", "/");
    sshPrivateKeyPath += "/.ssh/id_rsa";
}
console.info("set sshPrivateKeyPath=" + sshPrivateKeyPath);

function GitClient(localPath) {
    if (null == localPath || "" === localPath.trim()) {
        throw "localPath is empty";
    }
    this.localPath = localPath;
    // 使用包下带的私钥进行连接.
    var sessionFactory = new JschConfigSessionFactory({
        createDefaultJSch: function (fs) {
            // 注意这里的对象为 sessionFactory.
            var jsch = Java.super(sessionFactory).createDefaultJSch(fs);
            jsch.addIdentity(null, util.readToByteBuffer(sshPrivateKeyPath), null, null);
            return jsch;
        },
        configure: function(hc, session) {
            session.setConfig("StrictHostKeyChecking", "no");
        }
    }) ;
    SshSessionFactory.setInstance(sessionFactory);

    // 克隆一个仓库.
    this.cloneGit = function (remoteUrl) {
        if (!remoteUrl.startsWith("git@") && !remoteUrl.startsWith("ssh://git@")) {
            console.info("only support git@xx.com:/xx.gi");
            return;
        }
        var clone = Git.cloneRepository().setURI(remoteUrl).setDirectory(new File(this.localPath));
        var repo = clone.call();
        try {
            console.info("clone success. branches: ");
            var commitList = repo.branchList().setListMode(ListBranchCommand.ListMode.ALL).call();
            for (var b in commitList) {
                console.info("    " + commitList[b].getName());
            }
        } catch (e) {
            e.printStackTrace(console.err);
        }
    };

    // 操作拉取更新.
    this.pullGit = function () {
        var git = Git.open(new File(this.localPath));
        var currRevCommit = git.log().setMaxCount(1).call().iterator().next();
        var pull = git.pull();
        var call = pull.call();
        if (!call.isSuccessful()) {
            console.info("pull failed, exit.");
            return;
        }
        var msg = call.getMergeResult().getMergeStatus().toString();
        if (!"Fast-forward".equals(msg)) {
            console.info(msg);
            return;
        }
        var repository = git.getRepository();
        console.info("pull success, commits: ");
        var commitList = git.log().addRange(currRevCommit, git.log().
                setMaxCount(1).call().iterator().next()).call();
        commitList.forEach(function (revCommit) {
            console.info("    " + revCommit.getName() + "  " +
                    revCommit.getAuthorIdent().getName() + "   " + revCommit.getFullMessage());
        });
        console.info("pull success, files: ");
        var start = this.prepareTreeParser(repository, currRevCommit);
        var end = this.prepareTreeParser(repository, git.log().setMaxCount(1).call().iterator().next());
        var diff = git.diff().setOldTree(start).setNewTree(end).call();
        for (var diffEntry in diff) {
            console.info("    " + diff[diffEntry].toString());
        }
    };

    // 提交.
    this.commitGit = function (commitMsg) {
        var git = Git.open(new File(this.localPath));
        //提交
        var call = git.commit().setAll(true).setMessage(commitMsg).call();
        console.info("commit success. " + call.getName() +
                "    " + call.getFullMessage());
    };

    // 推送到远程
    this.pushGit = function () {
        var git = Git.open(new File(this.localPath));
        //推送到远程
        var call = git.push().call();
        call.forEach(function (pushResult) {
            pushResult.getRemoteUpdates().forEach(function (remoteRefUpdate) {
               console.info(remoteRefUpdate.getStatus() + "   " +
                       remoteRefUpdate.getExpectedOldObjectId() + " -> " +
                       remoteRefUpdate.getNewObjectId());
            });
         });
        console.info("push success.");
    };

    // 添加更新.
    this.addGit = function () {
        var git = Git.open(new File(this.localPath));
        var call = git.add().addFilepattern(".").call();
        console.info("add success. call = " + call.getEntryCount());
    };
    
    this.addAllGit = function () {
        var git = Git.open(new File(this.localPath));
        var call = git.add().setUpdate(true).addFilepattern(".").call();
        console.info("addAll success. call = " + call.getEntryCount());
    };

    //打印变更
    this.showStatusChange = function(changeName, change) {
        if (change.isEmpty()) {
            return;
        }
        console.info(changeName + ": ");
        change.forEach(function (value) {
            console.info("    " + value)
        });
    };
    
    // 查看更新状态.
    this.statusGit = function () {
        var git = Git.open(new File(this.localPath));
        var call = git.status().call();

        this.showStatusChange("Added", call.getAdded());
        this.showStatusChange("Changed", call.getChanged());
        this.showStatusChange("Conflicting", call.getConflicting());
        this.showStatusChange("ConflictingStageState", call.getConflictingStageState());
        this.showStatusChange("Missing", call.getMissing());
        this.showStatusChange("Modified", call.getModified());
        this.showStatusChange("Removed", call.getRemoved());

        console.info("statusGit end.");
    };

    // 用于对比.
    this.prepareTreeParser = function (repository, commit) {
        var walk = new RevWalk(repository);
        var tree = walk.parseTree(commit.getTree().getId());
        var oldTreeParser = new CanonicalTreeParser();
        var oldReader = repository.newObjectReader();
        oldTreeParser.reset(oldReader, tree.getId());
        walk.dispose();
        return oldTreeParser;
    }
}